#ifndef __M_HOST_H__
#define __M_HOST_H__
#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"

// 我们之前在mq_exchange.hpp中和mq_queue.hpp和mq_binding.hpp中均使用了#define CREATE_TABLE等一系列的宏定义
// 这些宏定义在编译的时候会报警告，这是因为：他们之间会 宏定义冲突（redefined）
// 因为 C/C++ 的宏定义不遵守 “类作用域” 或 “函数作用域”
// 它是 预处理阶段的文本替换指令，作用域是从定义处到所在文件结束（或被 #undef 取消），与类、函数的作用域无关。

namespace zymq
{
    class VirtualHost 
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;

        VirtualHost(const std::string &hname, const std::string &parentdir, const std::string &dbfile) :_host_name(hname)
            ,_emp(std::make_shared<ExchangeManager>(dbfile))
            ,_mqmp(std::make_shared<MsgQueueManager>(dbfile))
            ,_bmp(std::make_shared<BindingManager>(dbfile))
            ,_mmp(std::make_shared<MessageManager>(parentdir))
        {
            QueueMap qm = _mqmp->allQueues();
            for(auto & q : qm)
                _mmp->initQueueMessage(q.first);
        }

        bool declareExchange(const std::string &name,
                             ExchangeType type, bool durable, bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            return _emp->declareExchange(name, type, durable, auto_delete, args);
        }
        void deleteExchange(const std::string &name)
        {
            // 删除交换机时，需要先删除交换机的绑定信息
            _bmp->removeExchangeBindings(name);
            return _emp->deleteExchange(name);
        }
        bool existsExchange(const std::string &name)
        {
            return _emp->exists(name);
        }
        Exchange::ptr selectExchange(const std::string &ename)
        {
            return _emp->selectExchange(ename);
        }

        bool declareQueue(const std::string &name,
                             bool durable, bool exclusive, bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            // 先创建该队列的消息句柄
            // 再创建队列
            _mmp->initQueueMessage(name);
            return _mqmp->declareQueue(name, durable, exclusive, auto_delete, args);
        }                     
        void deleteQueue(const std::string &name)
        {
            // 删除队列中存储的信息
            // 删除队列所包含的绑定信息
            // 最后删除队列
            _mmp->destroyQueueMessage(name);
            _bmp->removeMsgQueueBindings(name);
            _mqmp->deleteQueue(name);
        }
        bool existsQueue(const std::string &name)
        {
            return _mqmp->exists(name);
        }
        QueueMap allQueues()
        {
            return _mqmp->allQueues();
        }

        bool bind(const std::string &ename, const std::string &qname, const std::string &key)
        {
            // 交换机不存在，不绑定
            // 队列不存在，不绑定
            // 交换机&&队列均持久化，则该绑定信息持久化
            Exchange::ptr ep = _emp->selectExchange(ename);
            if(ep.get() == nullptr)
            {
                DLOG("进行队列绑定失败,交换机%s不存在!",ename.c_str());
                return false;
            }

            MsgQueue::ptr mqp = _mqmp->selectQueue(qname);
            if(mqp.get() == nullptr)
            {
                DLOG("进行队列绑定失败,队列%s不存在!",qname.c_str());
                return false;
            }

            return _bmp->bind(ename, qname, key, ep->durable && mqp->durable);
        }
        void unBind(const std::string &ename, const std::string &qname)
        {
            _bmp->unBind(ename, qname);
        }
        MsgQueueBindingMap exchangeBindings(const std::string &ename)
        {
            return _bmp->getExchangeBindings(ename);
        }
        bool existsBinding(const std::string &ename, const std::string &qname)
        {
            return _bmp->exists(ename, qname);
        }

        bool basicPublish(const std::string &qname, BasicProperties *bp, const std::string &body)
        {
            MsgQueue::ptr mqp = _mqmp->selectQueue(qname);
            if(mqp.get() == nullptr)
            {
                DLOG("发布消息失败,队列%s不存在!",qname.c_str());
                return false;
            }
            return _mmp->insert(qname, bp, body, mqp->durable);
        }
        MessagePtr basicConsume(const std::string &qname)
        {
            return _mmp->front(qname);
        }
        void basicAck(const std::string &qname, const std::string &msg_id)
        {
            _mmp->ack(qname, msg_id);
        }
        void clear()
        {
            _emp->clear();
            _mqmp->clear();
            _bmp->clear();
            _mmp->clear();
        }
    private:
        std::string _host_name;
        ExchangeManager::ptr _emp; // 交换机管理句柄
        MsgQueueManager::ptr _mqmp; // 消息队列管理句柄
        BindingManager::ptr _bmp; // 绑定信息管理句柄
        MessageManager::ptr _mmp; // 队列消息管理句柄
    };
}

#endif